package api

import (
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"time"

	"zhonghui/console/models"
	"zhonghui/console/service"
	"zhonghui/console/structs"
	"zhonghui/console/warehouse/cfgx"
	"zhonghui/console/warehouse/dbx/db_zh_kernel"
	"zhonghui/console/warehouse/logx"
	"zhonghui/console/warehouse/respx"
	"zhonghui/console/wxutil"

	"github.com/gin-gonic/gin"
)

const cacheTime = time.Minute * 1

type GetEmployeeListRequest struct {
	CorpId string `form:"corp_id" binding:"required" validate:"max=64"`
}

// GetEmployeeList 获取员工列表, 用于配置页面, 为二维码配置员工
func (server *Server) GetEmployeeList(c *gin.Context) {

	req := GetEmployeeListRequest{}
	if err := c.ShouldBindQuery(&req); err != nil {
		logx.Zap().Errorw("GetEmployeeList ShouldBindQuery", "err", err)
		respx.Error(c, "parameter error", err)
		return
	}

	key := fmt.Sprintf("cache_GetEmployeeList-%s", req.CorpId)
	cache := wxutil.NewCache()
	val, err := cache.Get(key)
	if err == nil && val != nil {
		resp := []service.Employee{}
		err = json.Unmarshal([]byte(val.(string)), &resp)
		respx.Success(c, resp, nil)
		return
	}

	accessToken, err := server.store.GetAccessTokenByCorpId(context.Background(), req.CorpId)
	if err != nil {
		logx.Zap().Error("GetEmployeeList GetAccessTokenByCorpId", "err", err, "id", req.CorpId)
		respx.Error(c, "get access token err", err)
		return
	}

	list, err := service.GetEmployees(accessToken)
	if err != nil {
		logx.Zap().Error("GetEmployeeList GetEmployees", "err", err, "id", req.CorpId)
		respx.Error(c, err.Error(), err)
		return
	}

	cache.Set(key, list, cacheTime)

	respx.Success(c, list, nil)
}

type ActiveEmployeeRequest struct {
	CorpId string `json:"corp_id" binding:"required" validate:"max=64"`
	UserId string `json:"user_id" binding:"required" validate:"max=64"`
	Code   string `json:"code" binding:"required" validate:"max=64"`
}

func (server *Server) ActiveEmployee(c *gin.Context) {

	req := ActiveEmployeeRequest{}
	if err := c.ShouldBindJSON(&req); err != nil {
		logx.Zap().Errorw("GetActiveCodeList ShouldBindQuery", "err", err)
		respx.Error(c, "parameter error", err)
		return
	}
	cache := wxutil.NewCache()
	cfg := cfgx.Cfg().GetStringMapString("wx")
	token, err := wxutil.GetProviderAccessToken(cfg["corp_id"])
	if err != nil {
		logx.Zap().Error("GetActiveOrderList GetProviderAccessToken", "err", err)
		respx.Error(c, "get access token err", err)
		return
	}

	// do scan
	s, err := service.GetUserActiveStatus(token, cfg["corp_id"], req.UserId)
	if err != nil {
		logx.Zap().Error("GetEmployeeActiveStatus GetUserActiveStatus", "err", err)
		respx.Error(c, "get access token err", err)
		return
	}
	if s.Errcode == 0 && s.ActiveStatus == 1 {
		// 已经激活了,直接成功
		cache.Client().Set(context.Background(),
			fmt.Sprintf(structs.ActiveExpireKey, req.CorpId, req.UserId), "active", time.Hour*24*30)
		server.store.CreateActiveCode(context.Background(), req.Code)
		respx.Success(c, "ok", nil)
		return
	}

	r, err := service.ActiveUser(token, req.CorpId, req.UserId, req.Code)
	if err != nil {
		logx.Zap().Error("GetActiveOrderList GetProviderAccessToken", "err", err)
		respx.Error(c, "get access token err", err)
		return
	}
	if r.Errcode != 0 {
		logx.Zap().Error("GetActiveOrderList GetProviderAccessToken", "err", r.Errmsg)
		respx.Error(c, fmt.Sprintf("激活失败:%s", r.Errmsg), errors.New(r.Errmsg))
		return
	}

	cache.Client().Set(context.Background(),
		fmt.Sprintf(structs.ActiveExpireKey, req.CorpId, req.UserId), "active", time.Hour*24*30)
	server.store.CreateActiveCode(context.Background(), req.Code)
	respx.Success(c, "ok", nil)
}

type GetEmployeeActiveStatusRequest struct {
	CorpId string `form:"corp_id" binding:"required" validate:"max=64"`
	UserId string `form:"user_id" binding:"required" validate:"max=64"`
}

func (server *Server) GetEmployeeActiveStatus(c *gin.Context) {

	req := GetEmployeeActiveStatusRequest{}
	if err := c.ShouldBindQuery(&req); err != nil {
		logx.Zap().Errorw("GetEmployeeActiveStatus ShouldBindQuery", "err", err)
		respx.Error(c, "parameter error", err)
		return
	}

	cfg := cfgx.Cfg().GetStringMapString("wx")

	token, err := wxutil.GetProviderAccessToken(cfg["corp_id"])
	if err != nil {
		logx.Zap().Error("GetActiveOrderList GetProviderAccessToken", "err", err)
		respx.Error(c, "get access token err", err)
		return
	}

	s, err := service.GetUserActiveStatus(token, cfg["corp_id"], req.UserId)
	if err != nil {
		logx.Zap().Error("GetEmployeeActiveStatus GetUserActiveStatus", "err", err)
		respx.Error(c, "get access token err", err)
		return
	}
	if s.Errcode != 0 {
		logx.Zap().Error("GetEmployeeActiveStatus GetUserActiveStatus", "err", s.Errmsg)
		respx.Error(c, fmt.Sprintf("获取失败:%s", s.Errmsg), errors.New(s.Errmsg))
		return
	}

	respx.Success(c, s.ActiveStatus, nil)
}

type GetActiveCodeList struct {
	CorpId  string `form:"corp_id" binding:"required" validate:"max=64"`
	OrderId string `form:"order_id" binding:"required" validate:"max=64"`
}

func (server *Server) GetActiveCodeList(c *gin.Context) {

	req := GetActiveCodeList{}
	if err := c.ShouldBindQuery(&req); err != nil {
		logx.Zap().Errorw("GetActiveCodeList ShouldBindQuery", "err", err)
		respx.Error(c, "parameter error", err)
		return
	}

	cfg := cfgx.Cfg().GetStringMapString("wx")
	token, err := wxutil.GetProviderAccessToken(cfg["corp_id"])
	if err != nil {
		logx.Zap().Error("GetActiveOrderList GetProviderAccessToken", "err", err)
		respx.Error(c, "get access token err", err)
		return
	}

	list, err := service.GetActiveCodeList(token, req.OrderId, cfg["corp_id"])
	if err != nil {
		logx.Zap().Error("GetActiveCodeList GetActiveCodeList", "err", err)
		respx.Error(c, "get active code list err", err)
		return
	}
	if list.Errcode != 0 {
		logx.Zap().Error("GetActiveCodeList GetActiveCodeList", "err", list.Errmsg)
		respx.Error(c, "get active code list err", errors.New(list.Errmsg))
		return
	}

	// 排除已经激活的
	var codeList []string
	var resp []service.GetActiveCodeListItem
	for _, v := range list.AccountList {
		codeList = append(codeList, v.ActiveCode)
	}
	var ret []models.SysActiveCode
	rm := make(map[string]bool)
	db_zh_kernel.Client().
		Table("sys_active_code").
		Where("code in (?)", codeList).Find(&ret)
	for _, v := range ret {
		rm[v.Code] = true
	}
	for _, v := range list.AccountList {
		if _, ok := rm[v.ActiveCode]; !ok {
			resp = append(resp, v)
		}
	}
	// 排除已经激活的

	respx.Success(c, resp, nil)
}

type GetActiveOrderListRequest struct {
	CorpId string `form:"corp_id" binding:"required" validate:"max=64"`
}

func (server *Server) GetActiveOrderList(c *gin.Context) {

	cfg := cfgx.Cfg().GetStringMapString("wx")

	cache := wxutil.NewCache()
	val, err := cache.Get("cache_GetActiveOrderList")
	if err == nil && val != nil {
		resp := service.GetActiveCodeOrderListResponse{}
		err = json.Unmarshal([]byte(val.(string)), &resp)
		respx.Success(c, resp.OrderList, nil)
		return
	}

	token, err := wxutil.GetProviderAccessToken(cfg["corp_id"])
	if err != nil {
		logx.Zap().Error("GetActiveOrderList GetProviderAccessToken", "err", err)
		respx.Error(c, "get access token err", err)
		return
	}

	list, err := service.GetActiveCodeOrderList(token, cfg["corp_id"])
	if err != nil {
		logx.Zap().Error("GetActiveOrderList GetActiveCodeOrderList", "err", err)
		respx.Error(c, "get active code order list err", err)
		return
	}
	if list.Errcode != 0 {
		logx.Zap().Error("GetActiveOrderList GetActiveCodeOrderList", "err", list.Errmsg)
		respx.Error(c, list.Errmsg, errors.New(list.Errmsg))
		return
	}

	cache.Set("cache_GetActiveOrderList", list, cacheTime)

	respx.Success(c, list.OrderList, nil)
}
